﻿using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;

namespace Abide.Forms
{
    public partial class CreateAddOnDialog : Form
    {
        public string AddOnName
        {
            get { return nameBox.Text; }
            set { nameBox.Text = value; }
        }
        public string UpdateUrl
        {
            get { return updateUrlBox.Text; }
            set { updateUrlBox.Text = value; }
        }
        public string[] SelectedFiles
        {
            get
            {
                //Prepare
                List<string> files = new List<string>();
                DirectoryInfo directoryInfo = null;
                FileInfo fileInfo = null;

                //Loop
                foreach (TreeNode node in fileView.Nodes)
                {
                    //Check
                    if (node.Tag is FileInfo)
                    {
                        fileInfo = node.Tag as FileInfo;
                        if (node.Checked)
                            files.Add(fileInfo.FullName);
                    }
                    else if (node.Tag is DirectoryInfo)
                    {
                        directoryInfo = node.Tag as DirectoryInfo;
                        if (node.Checked)
                            files.AddRange(LoopFiles(node));
                    }
                }

                //Return
                return files.ToArray();
            }
        }
        public string[] SelectedDirectories
        {
            get
            {
                //Prepare
                List<string> directories = new List<string>();
                DirectoryInfo directoryInfo = null;

                //Loop
                foreach (TreeNode node in fileView.Nodes)
                {
                    //Check
                    if (node.Tag is DirectoryInfo)
                    {
                        directoryInfo = node.Tag as DirectoryInfo;
                        if (node.Checked)
                            directories.AddRange(LoopDirectories(node));
                    }
                }

                //Return
                return directories.ToArray();
            }
        }

        private string[] LoopDirectories(TreeNode owner)
        {
            //Prepare
            List<string> directories = new List<string>();
            DirectoryInfo directoryInfo = null;

            //Loop
            foreach (TreeNode node in owner.Nodes)
            {
                //Check
                if (node.Tag is DirectoryInfo)
                {
                    directoryInfo = node.Tag as DirectoryInfo;
                    if (node.Checked)
                        directories.AddRange(LoopDirectories(node));
                }
            }

            //Return
            return directories.ToArray();
        }
        private string[] LoopFiles(TreeNode owner)
        {
            //Prepare
            List<string> files = new List<string>();
            DirectoryInfo directoryInfo = null;
            FileInfo fileInfo = null;

            //Loop
            foreach (TreeNode node in owner.Nodes)
            {
                //Check
                if (node.Tag is FileInfo)
                {
                    fileInfo = node.Tag as FileInfo;
                    if (node.Checked)
                        files.Add(fileInfo.FullName);
                }
                else if (node.Tag is DirectoryInfo)
                {
                    directoryInfo = node.Tag as DirectoryInfo;
                    if (node.Checked)
                        files.AddRange(LoopFiles(node));
                }
            }

            //Return
            return files.ToArray();
        }

        public CreateAddOnDialog()
        {
            InitializeComponent();
        }
        private void CreateAddOnDialog_Load(object sender, System.EventArgs e)
        {
            //Add
            foreach (string url in Properties.Settings.Default.AddOnUpdateUrls)
                updateUrlBox.Items.Add(url);

            //Check
            if (Properties.Settings.Default.AddOnUpdateUrls.Count > 0)
                updateUrlBox.SelectedIndex = 0;
        }
        public void LoadFiles(string root)
        {
            //Prepare
            TreeNode node = null;

            //Get Directories and Files
            string[] Directories = Directory.GetDirectories(root);
            string[] Files = Directory.GetFiles(root);

            //Loop and add Directories
            foreach (string directory in Directories)
            {
                //Create
                node = new TreeNode(directory.Replace(root, string.Empty).Substring(1));
                node.Tag = new DirectoryInfo(directory);
                node.Checked = true;

                //Load Subdirectories and files
                BuildTree(node, directory);

                //Add
                fileView.Nodes.Add(node);
            }

            //Add Files
            foreach (string file in Files)
            {
                //Create
                node = new TreeNode(file.Replace(root, string.Empty).Substring(1));
                node.Tag = new FileInfo(file);
                node.Checked = true;

                //Add
                fileView.Nodes.Add(node);
            }

            //Expand
            fileView.ExpandAll();
        }
        private void BuildTree(TreeNode owner, string root)
        {
            //Prepare
            TreeNode node = null;

            //Get Directories and Files
            string[] Directories = Directory.GetDirectories(root);
            string[] Files = Directory.GetFiles(root);

            //Loop and add Directories
            foreach (string directory in Directories)
            {
                //Create
                node = new TreeNode(directory.Replace(root, string.Empty).Substring(1));
                node.Tag = new DirectoryInfo(directory);
                node.Checked = true;

                //Load Subdirectories and files
                BuildTree(node, directory);

                //Add
                owner.Nodes.Add(node);
            }

            //Add Files
            foreach (string file in Files)
            {
                //Create
                node = new TreeNode(file.Replace(root, string.Empty).Substring(1));
                node.Tag = new FileInfo(file);
                node.Checked = true;

                //Add
                owner.Nodes.Add(node);
            }
        }
        private void enableUpdateCheckBox_CheckedChanged(object sender, System.EventArgs e)
        {
            updateUrlBox.Enabled = enableUpdateCheckBox.Checked;
        }
        private void fileView_AfterCheck(object sender, TreeViewEventArgs e)
        {
            //Recursive Uncheck
            if (!e.Node.Checked)
                foreach (TreeNode node in e.Node.Nodes)
                    node.Checked = false;
        }
        private void okButton_Click(object sender, System.EventArgs e)
        {
            //Check
            if (updateUrlBox.Text != null)
            {
                if (Properties.Settings.Default.AddOnUpdateUrls == null)
                    Properties.Settings.Default.AddOnUpdateUrls = new System.Collections.Specialized.StringCollection();

                Properties.Settings.Default.AddOnUpdateUrls.Remove(updateUrlBox.Text);
                Properties.Settings.Default.AddOnUpdateUrls.Insert(0, updateUrlBox.Text);
                Properties.Settings.Default.Save();
            }
        }
        public string CreateZip(string root, string primaryAssembly)
        {
            //Get Index
            int Index = root.Length + (root.EndsWith("\\") ? 0 : 1);

            //Create Temp File
            string tempFile = Path.GetTempFileName();
            string ManifestFile = Path.GetTempFileName();

            //Create Manifest
            Classes.AddOnManifest Manifest = new Classes.AddOnManifest();
            Manifest.Name = AddOnName;
            Manifest.UpdateInfoUrl = UpdateUrl;
            Manifest.PrimaryAssembly = primaryAssembly.Substring(Index);
            foreach (string path in SelectedFiles)
                Manifest.AddFile(path.Substring(Index));
            foreach (string path in SelectedDirectories)
                Manifest.AddDirectory(path.Substring(Index));
            Manifest.Write(ManifestFile);

            //Write Zip File
            using (FileStream fs = File.OpenWrite(tempFile))
            {
                //Prepare
                ZipOutputStream zipStream = new ZipOutputStream(fs);
                zipStream.IsStreamOwner = true;
                ZipEntry entry = null;
                FileInfo info = null;
                byte[] buffer = null;

                //Add Manifest
                info = new FileInfo(ManifestFile);
                entry = new ZipEntry("Manifest.xml");
                entry.DateTime = DateTime.Now;
                zipStream.PutNextEntry(entry);

                //Write
                buffer = new byte[4096];
                using (FileStream streamReader = File.OpenRead(ManifestFile))
                    StreamUtils.Copy(streamReader, zipStream, buffer);
                zipStream.CloseEntry();

                //Get Files
                foreach (string file in Manifest.FileNames)
                {
                    //Create
                    info = new FileInfo(file);
                    entry = new ZipEntry(ZipEntry.CleanName(file));
                    entry.DateTime = info.CreationTime;
                    zipStream.PutNextEntry(entry);

                    //Write
                    buffer = new byte[4096];
                    using (FileStream streamReader = File.OpenRead(Path.Combine(root, file)))
                        StreamUtils.Copy(streamReader, zipStream, buffer);
                    zipStream.CloseEntry();
                }

                //Close
                zipStream.Close();
            }

            //Return
            return tempFile;
        }
    }
}
